<?php

namespace App\Jobs;

use App\Http\Traits\CacheTrait;
use App\Models\RepoSetting;
use Cache;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
use Storage;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;

class Deploy extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    private $namespace;
    private $env;
    private $branch;
    private $user_name;
    private $app_path;
    private $ssh_host;
    private $repo_url;
    private $app_logs_path;
    private $app_configs_path;
    private $setting_name;
    private $repo_path;
    private $work_dir;
    private $include_paths;
    private $setting_id;
    private $checkout_sha;
    private $exclude_files;

    use CacheTrait;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($params)
    {
        $this->namespace        = $params['repo_namespace'];
        $this->branch           = $params['branch'];
        $this->env              = $params['server_env'];
        $this->user_name        = $params['user_name'];
        $this->ssh_host         = $params['ssh_host'];
        $this->repo_url         = $params['repo_url'];
        $this->app_path         = $params['app_path'];
        $this->app_logs_path    = $params['app_logs_path'];
        $this->app_configs_path = $params['app_configs_path'];
        $this->setting_name     = $params['name'];
        $this->repo_path        = $params['repo_path'];
        $this->work_dir         = $params['work_dir'];
        $this->include_paths    = (isset($params['include_paths']) ? $params['include_paths'] : '') ?: 0;
        $this->exclude_files    = (isset($params['exclude_files']) ? $params['exclude_files'] : '') ?: 0;
        $this->setting_id       = $params['id'];
        $this->checkout_sha     = $params['checkout_sha'];
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $this->forgetLog();
        try {
            $process = $this->process();
            Log::info(__FUNCTION__ . '$command_line', ['command line' => $process->getCommandLine()]);
            $new_process = new Process($process->getCommandLine() . ' --load-from ' . base_path());
            $new_process->setTimeout(null);
            $new_process->mustRun(function ($type, $buffer) {
                if (strlen(strip_tags($buffer)) > 8) {
                    Log::debug($this->user_name . '>>' . $this->env . '>>' . $this->namespace, [$buffer]);
                }

                if (strpos($buffer, 'deploy_success') !== false) {
                    RepoSetting::find($this->setting_id)->update(['last_sha_id' => $this->checkout_sha]);
                }
            });
            $output = $new_process->getOutput();
            print_r($output);
            $this->setLog($output);
        } catch (ProcessFailedException $e) {
            $this->pubuNotice('部署异常！！！', $e->getMessage());
        } catch (ProcessTimedOutException $e) {
            $this->pubuNotice('部署超时！！！', $e->getMessage());
        }

        try {
            Storage::delete([
                storage_path('app/' . $this->checkout_sha . '.lock'),
                storage_path('app/' . $this->ssh_host . '_' . str_replace('/', '_', $this->app_path) . '.lock'),
            ]);
            Cache::forget('cache_sha:' . $this->checkout_sha);
        } catch (\Exception $e) {
            // everything is ok.
        }
    }

    public function forgetLog()
    {
        $this->forgetDeployProcessLog($this->user_name, $this->env, $this->namespace);
    }

    public function setLog($log)
    {
        $this->setDeployProcessLog($this->user_name, $this->env, $this->namespace, $log);
    }

    public function pubuNotice($msg, $exceptions)
    {
        $this->setLog($msg . PHP_EOL . '> exception message: ' . $exceptions);
        $msg = 'payload={"text": "【 ' . $this->namespace . ' 】【' . $this->setting_name . '】【 ' . $this->env . ' 】' . $msg . '"}';
        system("curl https://hooks.pubu.im/services/prpnk9xel3rxf8m -X POST --data-urlencode '" . $msg . "'");
    }

    public function process()
    {
        $process_builder = new ProcessBuilder();
        $process_builder->setPrefix('robo');
        //$process_builder->setPrefix(base_path('vendor/bin/robo'));
        $process_builder->setArguments([
            'deploy',
            $this->namespace,
            $this->env,
            $this->branch,
            $this->user_name,
            $this->ssh_host,
            $this->repo_url,
            $this->checkout_sha,
            $this->app_path,
            $this->repo_path,
            $this->work_dir,
            $this->setting_name,
            $this->app_logs_path,
            $this->app_configs_path,
            $this->include_paths,
            $this->exclude_files,
        ]);

        return $process_builder->getProcess();
    }
}
